home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_400 / 409_01 / cpu.asm < prev    next >
Assembly Source File  |  1993-10-20  |  11KB  |  256 lines

  1. ;****************************************************************************
  2. ;*
  3. ;*                            The MegaToolbox
  4. ;*
  5. ;*                  Copyright (C) 1993 SciTech Software
  6. ;*                          All rights reserved.
  7. ;*
  8. ;* Filename:    $RCSfile: cpu.asm $
  9. ;* Version:     $Revision: 1.1 $
  10. ;*
  11. ;* Language:    8086 Assembler
  12. ;* Environment: IBM PC (MS DOS)
  13. ;*
  14. ;* Description: Autodetection routine to determine the type of CPU installed
  15. ;*              in the system.
  16. ;*
  17. ;* $Id: cpu.asm 1.1 1993/09/02 11:04:55 kjb Exp $
  18. ;*
  19. ;****************************************************************************
  20.  
  21.         IDEAL
  22.  
  23. INCLUDE "model.mac"             ; Memory model macros
  24.  
  25. header  cpu                     ; Set up memory model
  26.  
  27. ;****************************************************************************
  28. ;
  29. ; Equates used by queryCPU routine.
  30. ;
  31. ;****************************************************************************
  32.  
  33. ; Central Processing Unit type codes
  34.  
  35. CPU86       =   0               ; 8086/88 type processor
  36. CPU186      =   1               ; 80186 type processor
  37. CPU286      =   2               ; 80286 type processor
  38. CPU286p     =   3               ; 80286 type processor in protected mode
  39. CPU386      =   4               ; 80386 type processor
  40. CPU386p     =   5               ; 80386 type processor in protected mode
  41. CPU486      =   6               ; 80486 type processor
  42. CPU486p     =   7               ; 80486 type processor in protected mode
  43.  
  44. ; Floating Point Unit type codes
  45.  
  46. FPUNONE     =   0               ; No coprocessor present
  47. FPU87       =   1               ; 8087 coprocessor
  48. FPU287      =   2               ; 80287 coprocessor
  49. FPU387      =   3               ; 80387 coprocessor
  50. FPU487      =   4               ; 80487 coprocessor
  51.  
  52. begcodeseg  cpu                 ; Start of code segment
  53.  
  54. P386                            ; Enable all '386 instructions
  55. P387                            ; Enable all '387 instructions
  56.  
  57. ; Save the type of CPU detected so we can determine the co-processor
  58. ; type correctly. This means that we MUST call queryCpu() BEFORE calling
  59. ; queryFpu() to obtain correct results.
  60.  
  61. cpu         dw  CPU86
  62.  
  63. ;----------------------------------------------------------------------------
  64. ; cpu_type queryCpu(void)
  65. ;----------------------------------------------------------------------------
  66. ; Determine type of processor present.
  67. ;----------------------------------------------------------------------------
  68. procstart   _queryCpu
  69.  
  70.         push    bp              ; We MUST save bp for initialization code...
  71.  
  72.         mov     ax,CPU86        ; Default to 8086/8088 processor
  73.         push    sp
  74.         pop     bx              ; BX holds the value of SP or SP-2
  75.         cmp     bx,sp           ; 88/86/186 pushes the value of SP-2
  76.         je      @@Check286      ; Must be a 286/386/486 type processor
  77.         mov     cl,32           ; 186 uses count mod 32 = 0
  78.         shl     bx,cl           ; 86 shifts 32 bits left so ax = 0
  79.         jz      @@Done          ; zero: shifted out all bits so 86/88
  80.         mov     ax,CPU186       ; nonzero: no shift, so 186
  81.         jz      @@Done
  82.  
  83. @@Check286:                     ; First check for 386/486 in 32 bit mode
  84.         pushf                   ; Test for 16 or 32 operand size:
  85.         mov     bx,sp           ;  pushed 2 or 4 bytes of flags
  86.         popf
  87.         inc     bx
  88.         inc     bx
  89.         cmp     bx,sp           ; did pushf change sp by 2?
  90.         jnz     @@Check486      ; 32 bit push, so it is a 386/486
  91.  
  92.         sub     sp,6            ; Is it a 286/386/486 in 16 bit mode?
  93.         mov     bp,sp
  94.         sgdt    [QWORD ptr bp]  ; 80286/386/486 specific instrucion
  95.         add     sp,4            ; Get global descriptor table
  96.         pop     bx
  97.         inc     bh              ; Third word of GDT = -1 for 286
  98.         jnz     @@Check486      ; We have a 386/486
  99.  
  100.         mov     ax,CPU286       ; We have a 286
  101.         jmp     @@TestPROT
  102.  
  103. @@Check486:
  104.  
  105. ; Distinguish an 80386 from an 80486. Bit 18 (40000H) of EFLAGS register
  106. ; is used only in the 486. This code flips it and tests if anything happened.
  107.  
  108.         mov     edx,esp         ; Save stack pointer
  109.         and     esp,not 3       ; Align stack pointer to prevent a fault
  110.                                 ;  when we set the AC flag on a 486
  111.         pushfd                  ; Copy the EFLAGS register
  112.         pop     eax             ;   into register eax
  113.         mov     ecx,eax         ; Save the original EFLAGS value
  114.         xor     eax,40000H      ; Flip the AC flag bit
  115.         push    eax             ; Try to put the modified value back
  116.         popfd                   ;   into the EFLAGS register
  117.         pushfd                  ; Copy the EFLAGS register again
  118.         pop     eax             ;   into eax
  119.         xor     eax,ecx         ; Compare the old and new AC bits
  120.         shr     eax,18          ; Shift and mask to get the AC comparison bit
  121.         and     eax,1           ;   in the low order position of eax
  122.         push    ecx
  123.         popfd                   ; Restore EFLAGS that were saved on entry
  124.         mov     esp,edx         ; And restore stack pointer to saved value
  125.         mov     bx,ax           ; and move into bx
  126.  
  127. ; At this point ax = 0 for a 386, or ax = 1 for a 486
  128.  
  129.         mov     ax,CPU386       ; Assume a 386
  130.         test    bx,bx
  131.         jz      @@TestPROT      ; We have a 386
  132.         mov     ax,CPU486       ; We have a 486
  133.  
  134. @@TestPROT:
  135.         smsw    cx              ; protected? machine status -> cx
  136.         ror     cx,1            ; protection bit -> carry flag
  137.         jnc     @@Done          ; Real mode if no carry
  138.         inc     ax              ; Protected: return value + 1
  139.  
  140. @@Done:
  141.         mov     [cpu],ax        ; Save CPU type in code segment variable
  142.         pop     bp              ; Restore bp
  143.         ret                     ; We are done
  144.  
  145. procend     _queryCpu
  146.  
  147. ndp_cw  dw  ?
  148. ndp_sw  dw  ?
  149.  
  150. ;----------------------------------------------------------------------------
  151. ; fpu_type queryFpu(void)
  152. ;----------------------------------------------------------------------------
  153. ; Determine type of floating point coprocessor present in the system.
  154. ; The idea is to determine whether or not the floating-point control word
  155. ; can be successfully read. If it cannot, then no coprocessor exists.
  156. ; If it can the correct coprocessor is then determined depending on the
  157. ; main CPU id.
  158. ;----------------------------------------------------------------------------
  159. procstart   _queryFpu
  160.  
  161.         push    bp
  162.  
  163.         mov     bx,FPUNONE      ; Default to no FPU present
  164.  
  165. ; The next two 80x87 instructions cannot carry the WAIT prefix,
  166. ; because there may not be an 80x87 for which to wait.  The WAIT is
  167. ; therefore emulated with a MOV CX,<value> LOOP $ combination.
  168.  
  169.         mov     [ndp_cw],0      ; Clear the control word in memory
  170.         cli                     ; Interrupts must be off during test
  171.  
  172.         fninit                  ; reset NDP status word
  173.         mov     cx,2            ; Wait for co-pro to complete operation
  174.         loop    $
  175.  
  176.         fnstcw  [ndp_cw]        ; Obtain the processor control word
  177.         mov     cx,14h          ; Wait for co-pro to complete operation
  178.         loop    $
  179.  
  180.         sti                     ; Re-enable interrupts
  181.  
  182. ; We check to see that the precison control bits of the control word
  183. ; indicate 64 bit internal precision (bits 8 & 9 set) which is the default
  184. ; set up by the fninit instruction above. We also test that the exception
  185. ; masks are properly set.
  186.  
  187.         mov     ax,[ndp_cw]     ; AX := NDP control word
  188.         and     ax,033fh        ; Mask out the precision control bits etc.
  189.         cmp     ax,033fh        ; is the NDP present?
  190.         jne     @@Done          ; No, we are all done... (must be a 3)
  191.  
  192. ; Determine the type of NDP from the main CPU type
  193.  
  194.         mov     bx,FPU87        ; Start with the 8087 NDP
  195.         mov     ax,[cpu]        ; Get current cpu type
  196.         cmp     ax,CPU286       ; >= 80286 t